local request_uri = ngx.var.uri
ngx.log(ngx.INFO, "uri:" .. request_uri)
-- 定义请求类型，1、http rest 2、grpc 3、ws，
-- 1、对于http和grpc需要将用户信息放入header
-- 2、对于ws需要对sec-websocket-protocol进行会写匹配ws模式的安全。
local request_scheme = ngx.var.req_scheme
if request_scheme == nil then
    ngx.log(ngx.ERR, "unknow " .. request_uri .. " request scheme!")
    ngx.exit(ngx.HTTP_NOT_ALLOWED)
end

-- prepare http rest | es grpc whitelist check
local whitelist_check = false
if request_scheme == "http" then
    local httpWhitelist = {
        "actuator", "api-docs", "prometheus", "healthy", --文档、监控类
        "addEsHost", "std/log/node", "searchPublicData", "getLastSuccessCodeSeqDebugRevealVarnames", "domainWhitelist", "authorization/callback", "simpleLogin", "check_token", --兼容某些老版本的api
        "v3/app/submit", "v3/app/kill", "v1/app/status", "api/v1/environment", "api/v1/status", "api/v1/healthcheck", "v1/app/submit" --gemini
    };
    for i, v in ipairs(httpWhitelist) do
        --print("index:", i, " value:", v)
        if string.find(request_uri, v) ~= nil then
            ngx.log(ngx.INFO, "current http uri " .. request_uri .. " whitelist check success!")
            whitelist_check = true
            break
        end
    end
elseif request_scheme == "grpc" then
    local verify_status = ngx.var.ssl_client_verify
    if verify_status == nil then
        ngx.log(ngx.INFO, "client verify status nil!")
    elseif verify_status == 'SUCCESS' then
        ngx.log(ngx.INFO, "current ssl_client_s_dn_legacy" .. ngx.var.ssl_client_s_dn_legacy)
        local ssl_dn_verify = ngx.var.ssl_dn_verify
        --if the whitelist map contains ssl_client_s_dn_legacy,domain access check success.
        if ssl_dn_verify ~= nil and ssl_dn_verify ~= "" then
            whitelist_check = true
            ngx.log(ngx.INFO, "current " .. ssl_dn_verify .. " domain whitelist check success!")
            return
        end
    else
        ngx.log(ngx.INFO, "client verify status:" .. verify_status)
    end
end

--prepare http、ds grpc sso authorization check
if not whitelist_check then
    -- request may grpc or websocket,if header have sec-websocket-protocol then websocket else grpc
    ngx.log(ngx.INFO, "prepare check sso!")
    local authorization = ngx.req.get_headers()["authorization"]
    -- websocket need origin_authorization to set response header for consistency
    local ws_authorization = ""
    if authorization == nil or authorization == "" then
        authorization = ngx.req.get_headers()["sec-websocket-protocol"]
        if authorization == nil or authorization == "" then
            ngx.log(ngx.ERR, "get header authorization fail!")
            ngx.exit(ngx.HTTP_UNAUTHORIZED)
            return
        end
        ws_authorization = authorization
        --判断是否包含Bearer,自行拼接Bearer
        if not string.find(authorization, "Bearer") then
            authorization = "Bearer " .. authorization
            ngx.log(ngx.INFO, "ws connect change authorization to :" .. authorization)
        end
    end

    local access_check_cache_map = require("access_check_cache")
    local access_check_value = access_check_cache_map.get(authorization)
    if access_check_value == nil or access_check_value == "" then
        local http = require("resty.http")
        local httpc = http:new()
        httpc:set_timeout(2000) -- 2S超时
        local sso_url = ngx.var.sso_url
        if sso_url == nil or sso_url == "" then
            ngx.log(ngx.ERR, "get init sso url fail!")
            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
            return
        end
        local sso_path = ngx.var.sso_path
        if sso_path == nil or sso_path == "" then
            ngx.log(ngx.ERR, "get init sso path fail!")
            ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
            return
        end
        ngx.log(ngx.INFO, "sso uri:" .. sso_url .. "/" .. sso_path)
        local resp, err = httpc:request_uri(sso_url,
                {
                    method = "GET",
                    path = "/" .. sso_path,
                    headers = { ["Authorization"] = authorization }
                    --keepalive_timeout = 2000, -- mill default lua_socket_keepalive_timeout
                    --keepalive_pool = 10 --default lua_socket_pool_size
                })
        if not resp then
            ngx.log(ngx.ERR, "sso request fail!     " .. err)
            ngx.exit(ngx.HTTP_BAD_REQUEST)
            return
        else
            --if sso server response status == 200, sso access check success.
            if resp.status == 200 then
                ngx.log(ngx.INFO, "sso check success!")
                local cjson = require("cjson.safe")
                local resp_json = cjson.decode(resp.body)
                if resp_json then
                    if resp_json.code == 0 then
                        local userJson = cjson.encode(resp_json.data)
                        ngx.log(ngx.INFO, "userJson:" .. userJson)
                        local userJsonBase64 = ngx.encode_base64(userJson)
                        ngx.log(ngx.INFO, "userJsonBase64:" .. userJsonBase64)
                        --添加请求头user_info
                        ngx.req.set_header("userInfo", userJsonBase64)
                        -- 放入缓存
                        access_check_cache_map.set(authorization, userJsonBase64, 20)
                        if request_scheme == "ws" then
                            ngx.var.ws_authorization = ws_authorization
                        else
                        end
                    else
                        ngx.log(ngx.ERR, "sso check fail! authorization:" .. authorization .. " message:" .. resp_json.msg)
                        ngx.exit(ngx.HTTP_UNAUTHORIZED)
                    end
                else
                    ngx.log(ngx.ERR, "sso resp parse json error! authorization:" .. authorization)
                    ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end
            elseif resp.status == 401 then
                ngx.log(ngx.ERR, "sso check fail! authorization:" .. authorization)
                ngx.exit(ngx.HTTP_UNAUTHORIZED)
            else
                ngx.log(ngx.ERR, "sso check fail! response code:" .. resp.status)
                ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
            end
        end
    else
        ngx.log(ngx.INFO, "access_check_value:" .. access_check_value)
        if request_scheme == "http" then
            --http请求需要继续携带cache的用户信息
            ngx.req.set_header("userInfo", access_check_value)
            --ngx.header["userInfo"] = access_check_value
        elseif request_scheme == "ws" then
            ngx.var.ws_authorization = ws_authorization
        else
        end
        ngx.log(ngx.INFO, "cache check sso success!")
    end

end